#pragma once

#include"Common.h"

#include"PlayerState.h"
#include"ProductionTask.h"

namespace Macro
{
	class Searcher
	{
	public:
		Searcher()
			:MAX_SCORE(1000000.0f),
			MIN_SCORE(-1000000.0f),
			_myState(Broodwar->self()),
			_enemyState(Broodwar->enemy())
		{
		}
		ProductionTask AlphaBeta(int maxFrame)
		{_evc=0;
			//_myState.SetWithGameState();
			//_enemyState.SetWithGameState();
			_frameLeft  = maxFrame;
			SpendType bestProduction;
			list<SpendType> myPossibleNexts;
			//--
			_myState.GetPossibleNexts(myPossibleNexts);
			if(myPossibleNexts.empty())
			{
			}
			else
			{
				float alpha(MIN_SCORE);
				float beta(MAX_SCORE);

				stringstream s;//
				for(list<SpendType>::const_iterator it = myPossibleNexts.begin() ; it != myPossibleNexts.end() ; ++it)
				{
					const SpendType& whichProduction(*it);
					_myState.SetNext(whichProduction);
					const float score = Min(alpha , beta);
					s << GetUnitType(whichProduction).getName() << ": " << score << " ";
					if(score > alpha)
					{
						alpha = score;
						bestProduction = whichProduction;
					}
				}
				s << "evaluate: " << _evc;
				Broodwar->printf("%s" , s.str().c_str());
			}

			ProductionTask answer;
			if(bestProduction == Lurker_Aspect)
			{
				answer = ProductionTask(TechTypes::Lurker_Aspect);
			}
			else if(bestProduction == Drone)
			{
				answer = ProductionTask(UnitTypes::Zerg_Drone);
			}
			else if(bestProduction == Zergling)
			{
				answer = ProductionTask(UnitTypes::Zerg_Zergling);
			}
			else if(bestProduction == Hydralisk)
			{
				answer = ProductionTask(UnitTypes::Zerg_Hydralisk);
			}
			else if(bestProduction == Overlord)
			{
				answer = ProductionTask(UnitTypes::Zerg_Overlord);
			}
			else if(bestProduction == Lurker)
			{
				answer = ProductionTask(UnitTypes::Zerg_Lurker);
			}
			else if(bestProduction == Hatchery)
			{
				answer = ProductionTask(UnitTypes::Zerg_Hatchery , 0);
			}
			else if(bestProduction == Lair)
			{
				answer = ProductionTask(UnitTypes::Zerg_Lair);
			}
			else if(bestProduction == Spawning_Pool)
			{
				answer = ProductionTask(UnitTypes::Zerg_Spawning_Pool , 0);
			}
			else if(bestProduction == Extractor)
			{
				answer = ProductionTask(UnitTypes::Zerg_Extractor , 0);
			}
			else if(bestProduction == Hydralisk_Den)
			{
				answer = ProductionTask(UnitTypes::Zerg_Hydralisk_Den , 0);
			}
			
			return answer;
		}
		const float MAX_SCORE;
		const float MIN_SCORE;
	private:
		float Evaluate()
		{
			++_evc;
			return _myState.SimulatedFight(_enemyState);
		}
		float Max(float alpha , float beta)
		{
			float maxNow(MIN_SCORE);
			list<SpendType> myPossibleNexts;
			//--
			_myState.GetPossibleNexts(myPossibleNexts);
			if(myPossibleNexts.empty())
			{
				return Tick(alpha , beta);
			}
			else
			{
				for(list<SpendType>::const_iterator it = myPossibleNexts.begin() ; it != myPossibleNexts.end() ; ++it)
				{
					const SpendType& whichProduction(*it);
					_myState.SetNext(whichProduction);
					const float score = Tick(alpha , beta);
					if(score > maxNow)
					{
						maxNow = score;
					}
					if(maxNow >= beta)
					{
						return maxNow;
					}
					if(maxNow > alpha)
					{
						alpha = maxNow;
					}
				}
				return maxNow;
			}
		}
		float Min(float alpha , float beta)
		{
			float minNow(MAX_SCORE);
			list<SpendType> enemyPossibleNexts;
			//--
			_enemyState.GetPossibleNexts(enemyPossibleNexts);
			if(enemyPossibleNexts.empty())
			{
				return Tick(alpha , beta);
			}
			else
			{
				for(list<SpendType>::const_iterator it = enemyPossibleNexts.begin() ; it != enemyPossibleNexts.end() ; ++it)
				{
					const SpendType& whichProduction(*it);
					_enemyState.SetNext(whichProduction);
					const float score = Tick(alpha , beta);
					if(score < minNow)
					{
						minNow = score;
					}
					if(minNow <= alpha)
					{
						return minNow;
					}
					if(minNow < beta)
					{
						beta = minNow;
					}
				}
				return minNow;
			}
		}
		float Tick(float alpha , float beta)
		{
			if(_myState.NextProductionNotSetted())
			{
				return Max(alpha , beta);
			}
			else if(_enemyState.NextProductionNotSetted())
			{
				return Min(alpha , beta);
			}
			else
			{
				const PlayerState originalMyState(_myState);
				const PlayerState originalEnemyState(_enemyState);
				const int originalFrameLeft(_frameLeft);
				float score(0.0f);
				while(true)
				{
					_myState.Tick();
					_enemyState.Tick();

					/*if(_myState.ArmySizeIncreasedInThisFrame() || _enemyState.ArmySizeIncreasedInThisFrame())
					{
						const float tempScore = Evaluate();
						const float TOO_MUCH = 100.0f;
						if(tempScore > TOO_MUCH || tempScore < -TOO_MUCH)
						{
							score = tempScore;
							goto END;
						}
					}*/

					--_frameLeft;
					if(_frameLeft <= 0)
					{
						score = Evaluate();
						goto END;
					}

					if(_myState.NextProductionNotSetted())
					{
						score = Max(alpha , beta);
						goto END;
					}

					if(_enemyState.NextProductionNotSetted())
					{
						score = Min(alpha , beta);
						goto END;
					}
				}
END:
				_myState = originalMyState;
				_enemyState = originalEnemyState;
				_frameLeft = originalFrameLeft;
				return score;
			}
		}
		//--
		PlayerState _myState;
		PlayerState _enemyState;
		int _frameLeft;
		int _evc;
	};
}